package logic

import (
	"fmt"
	"github.com/gogap/logs"
	"github.com/shopspring/decimal"
	"log"
	"math/rand"
	"sync"
	"time"
	"yundian/internel/app/dao"
	"yundian/internel/app/dao/memberdao"
	"yundian/internel/app/models/devices"
	"yundian/internel/app/models/membermodel"
	"yundian/internel/app/models/orders"
	"yundian/internel/app/models/refunds"
	"yundian/internel/app/models/users"
	"yundian/internel/pkg/dbs"
	"yundian/internel/pkg/dingo"
	"yundian/internel/pkg/dingo/global"
	"yundian/internel/pkg/utils"
)

type TaskRefundLogic struct {
}

func NewTaskRefundLogic() *TaskRefundLogic {
	return &TaskRefundLogic{}
}

// 分公司
func (t *TaskRefundLogic) BranchTranOrderToRefundByDraw(dateStr string, rate, settlement int64) {
	branchIds := dao.NewUserDao().GetTranUsersByIsAdmin(5).Unwrap().([]*users.UserIds)
	maxGoroutine := 4
	var pool chan struct{}
	pool = make(chan struct{}, maxGoroutine)
	var wg sync.WaitGroup
	for _, lst := range branchIds {
		wg.Add(1)
		pool <- struct{}{}
		go func(userId int) {
			defer wg.Done()
			defer func() {
				<- pool
			}()
			t.TranOrderToRefundAll(dateStr, userId, rate, settlement)
		}(lst.ID)
	}
	wg.Wait()
}

// 大区
func (t *TaskRefundLogic) AreaTranOrderToRefundByDraw() {

}

// 代理商
func (t *TaskRefundLogic) AgentTranOrderToRefundByDraw(dateStr string, rate, settlement int64) {
	branchIds := dao.NewUserDao().GetTranUsersByIsAdmin(8).Unwrap().([]*users.UserIds)
	maxGoroutine := 4
	var pool chan struct{}
	pool = make(chan struct{}, maxGoroutine)
	var wg sync.WaitGroup
	for _, lst := range branchIds {
		wg.Add(1)
		pool <- struct{}{}
		go func(userId int) {
			defer wg.Done()
			defer func() {
				<- pool
			}()
			t.TranOrderToRefundAll(dateStr, userId, rate, settlement)
		}(lst.ID)
	}
	wg.Wait()

}

// BD
func (t *TaskRefundLogic) BDTranOrderToRefundByDraw() {


}

// 合伙人
func (t *TaskRefundLogic) PartnerTranOrderToRefundByDraw(dateStr string, rate, settlement int64) {
	branchIds := dao.NewUserDao().GetTranUsersByIsAdmin(10).Unwrap().([]*users.UserIds)
	maxGoroutine := 4
	var pool chan struct{}
	pool = make(chan struct{}, maxGoroutine)
	var wg sync.WaitGroup
	for _, lst := range branchIds {
		wg.Add(1)
		pool <- struct{}{}
		go func(userId int) {
			defer wg.Done()
			defer func() {
				<- pool
			}()
			t.TranOrderToRefundAll(dateStr, userId, rate, settlement)
		}(lst.ID)
	}
	wg.Wait()

}


func (t *TaskRefundLogic) TranOrderToRefund(dateStr string, userId int, rate, settlement int64) {
	lst := dao.NewOrderDao().GetTranOrderByDraw(dateStr, userId).Unwrap().([]*orders.OrderModel)
	count := dao.NewOrderDao().CountTranOrderByDraw(dateStr, userId).Unwrap().(int64)

	//logs.Info("列表、总数", lst, count)
	// 要随机的总数
	total := decimal.NewFromInt(count).Mul(decimal.NewFromInt(rate).Div(decimal.NewFromInt(100))).IntPart()
	logs.Info("要随机的总数", total)
	rand.Seed(time.Now().UnixNano())
	rLst := t.RandInt(1, count, total)
	logs.Info("随机数组", rLst)
	lists1 := t.GetPlaceIdsByUserId(405391) //惠州
	lists2 := t.GetPlaceIdsByUserId(221) //分公司
	for _,l := range rLst {
		if utils.ContainsInt(lists1, lst[l].PlaceId) {
			continue
		}
		if utils.ContainsInt(lists2, lst[l].PlaceId) {
			continue
		}
		rMoney := decimal.NewFromInt(lst[l].SettlementMoney).Div(decimal.NewFromInt(100)).Mul(decimal.NewFromInt(settlement).Div(decimal.NewFromInt(100))).Ceil().IntPart() // 退款金额
		money := decimal.NewFromInt(lst[l].SettlementMoney).Sub(decimal.NewFromInt(rMoney).Mul(decimal.NewFromInt(100))).IntPart() // 退款之后的流水金额
		refundMoney := decimal.NewFromInt(rMoney).Mul(decimal.NewFromInt(100)).IntPart()

		// 新增退款记录
		m := refunds.New()
		m.RefundNo = ""   // 商户退款单号
		m.OutRefundNo = ""    // 微信退款号
		m.TradeNo = lst[l].TradeNo      // 商户订单号
		m.OutTradeNo = lst[l].OutTradeNo // 微信支付单号


		m.RefundAccount = ""
		m.RefundRecvAccout = ""
		m.RefundRequestSource = ""
		m.RefundStatus = ""

		m.RefundFee = refundMoney                       // 退款金额
		m.SettlementRefundFee = refundMoney             // 支付退款金额
		m.SettlementTotalFee = lst[l].SettlementMoney   // 订单支付金额
		m.TotalFee = lst[l].PayMoney

		m.Appid = ""
		m.Mchid = ""
		m.SuccessTime = dingo.Time(time.Now().Unix())
		m.CreateAt = dingo.Time(time.Now().Unix())
		m.UpdateAt = dingo.Time(time.Now().Unix())

		if c := dao.NewRefundDao().CountRefundByTradeNo(lst[l].TradeNo).Unwrap().(int64); c <= 0 { // 有过退款的不做操作
			// 回滚分红、重新分红
			if err := dao.NewOrderDao().DeleteDividendsLog(lst[l].TradeNo).Err; err == nil {
				if err := dao.NewRefundDao().InsertRefund(m).Err; err == nil {
					logs.Info("======== 退款记录新增成功 =========", lst[l].PayMoney)
					if err := dao.NewOrderDao().UpdateOrderSettlementMoney(lst[l].Id, money).Err; err == nil { // 订单修改成功
						devInfo := dao.NewOrderDao().GetDeviceInfo(lst[l].DeviceSn).Unwrap().(*devices.DeviceType)            // 获取设备信息
						dingo.Task(NewOrderLogic().CalOrderDividends, func() {}, lst[l], devInfo, money, int64(lst[l].EndAt)) // 重新分红
					}
				}
			}
		}
	}
}

func (t *TaskRefundLogic) TranOrderToRefundAll(dateStr string, userId int, rate, settlement int64) {
	lst := dao.NewOrderDao().GetTranOrderByDraw(dateStr, userId).Unwrap().([]*orders.OrderModel)
	count := dao.NewOrderDao().CountTranOrderByDraw(dateStr, userId).Unwrap().(int64)

	//logs.Info("列表、总数", lst, count)
	// 要随机的总数
	total := decimal.NewFromInt(count).Mul(decimal.NewFromInt(rate).Div(decimal.NewFromInt(100))).IntPart()
	logs.Info("要随机的总数", total)
	rand.Seed(time.Now().UnixNano())
	rLst := t.RandInt(1, count, total)
	logs.Info("随机数组", rLst)
	for _,l := range rLst {
		refundNo := utils.Join(global.Const.Pre.RefundPre, time.Now().Format("20060102150405"), utils.GetRandomInt(6)) // 退款订单号

		// 新增退款记录
		m := refunds.New()
		m.RefundNo = refundNo   // 商户退款单号
		m.OutRefundNo = utils.Join("5030240541", time.Now().Format("200601021504"), utils.GetRandomInt(6))    // 微信退款号
		m.TradeNo = lst[l].TradeNo      // 商户订单号
		m.OutTradeNo = lst[l].OutTradeNo // 微信支付单号

		m.RefundAccount = lst[l].Openid
		m.RefundRecvAccout = lst[l].Openid
		m.RefundRequestSource = "支付用户零钱"
		m.RefundStatus = "SUCCESS"

		m.RefundFee = lst[l].PayMoney                       // 退款金额
		m.SettlementRefundFee = lst[l].PayMoney             // 支付退款金额
		m.SettlementTotalFee = lst[l].SettlementMoney       // 订单支付金额
		m.TotalFee = lst[l].PayMoney

		m.Appid = lst[l].Appid
		m.Mchid = lst[l].Mchid
		m.SuccessTime = dingo.Time(time.Now().Unix())
		m.CreateAt = dingo.Time(time.Now().Unix())
		m.UpdateAt = dingo.Time(time.Now().Unix())

		m.IsRef = 1

		if c := dao.NewRefundDao().CountRefundByTradeNo(lst[l].TradeNo).Unwrap().(int64); c <= 0 { // 有过退款的不做操作
			// 回滚分红、重新分红
			if err := dao.NewOrderDao().DeleteDividendsLog(lst[l].TradeNo).Err; err == nil {
				if err := dao.NewRefundDao().InsertRefund(m).Err; err == nil {
					logs.Info("======== 退款记录新增成功 =========", lst[l].PayMoney)
					dao.NewOrderDao().UpdateOrderStatus(lst[l].TradeNo, 3)
				}
			}
		}
	}
}

func (t *TaskRefundLogic) RandInt(min, max, total int64) []int64 {
	var numRes []int64
	var i int64
	for i = 1; i <= total; i++ {
		num := rand.Int63n(max - min) + min
		numRes = append(numRes, num)
	}
	return numRes
}






// 普通订单
func (t *TaskRefundLogic) TranOrderToRefundByNoDraw(dateStr string, rate, settlement int64) {
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		t.TranNormalOrderToRefund(dateStr, rate, settlement)
	}()
	wg.Wait()
}

// 普通订单
func (t *TaskRefundLogic) TranNormalOrderToRefund(dateStr string, rate, settlement int64) {
	//logs.Info("进入--------------------")
	lst := dao.NewOrderDao().GetTranOrderByNoDraw(dateStr).Unwrap().([]*orders.OrderModel)
	//logs.Info("列表", lst)
	count := dao.NewOrderDao().CountTranOrderByNoDraw(dateStr).Unwrap().(int64)
	//logs.Info("总数", count)
	// 要随机的总数
	total := decimal.NewFromInt(count).Mul(decimal.NewFromInt(rate).Div(decimal.NewFromInt(100))).IntPart()
	//logs.Info("要随机的总数", total)
	rand.Seed(time.Now().UnixNano())
	rLst := t.RandInt(1, count, total)
	logs.Info("随机数组", rLst)
	lists1 := t.GetPlaceIdsByUserId(405391) //惠州
	lists2 := t.GetPlaceIdsByUserId(221) //广西
	for _,l := range rLst {
		if utils.ContainsInt(lists1, lst[l].PlaceId) {
			continue
		}
		if utils.ContainsInt(lists2, lst[l].PlaceId) {
			continue
		}
		rMoney := decimal.NewFromInt(lst[l].SettlementMoney).Div(decimal.NewFromInt(100)).Mul(decimal.NewFromInt(settlement).Div(decimal.NewFromInt(100))).Ceil().IntPart() // 退款金额
		money := decimal.NewFromInt(lst[l].SettlementMoney).Sub(decimal.NewFromInt(rMoney).Mul(decimal.NewFromInt(100))).IntPart() // 退款之后的流水金额
		refundMoney := decimal.NewFromInt(rMoney).Mul(decimal.NewFromInt(100)).IntPart()
		// 新增退款记录
		m := refunds.New()
		m.RefundNo = ""   // 商户退款单号
		m.OutRefundNo = ""    // 微信退款号
		m.TradeNo = lst[l].TradeNo      // 商户订单号
		m.OutTradeNo = lst[l].OutTradeNo // 微信支付单号


		m.RefundAccount = ""
		m.RefundRecvAccout = ""
		m.RefundRequestSource = ""
		m.RefundStatus = ""

		m.RefundFee = refundMoney                       // 退款金额
		m.SettlementRefundFee = refundMoney             // 支付退款金额
		m.SettlementTotalFee = lst[l].SettlementMoney   // 订单支付金额
		m.TotalFee = lst[l].PayMoney

		m.Appid = ""
		m.Mchid = ""
		m.SuccessTime = dingo.Time(time.Now().Unix())
		m.CreateAt = dingo.Time(time.Now().Unix())
		m.UpdateAt = dingo.Time(time.Now().Unix())

		if c := dao.NewRefundDao().CountRefundByTradeNo(lst[l].TradeNo).Unwrap().(int64); c <= 0 { // 有过退款的不做操作
			// 回滚分红、重新分红
			if err := dao.NewOrderDao().DeleteDividendsLog(lst[l].TradeNo).Err; err == nil {
				if err := dao.NewRefundDao().InsertRefund(m).Err; err == nil {
					logs.Info("======== 退款记录新增成功 =========", lst[l].PayMoney)
					if err := dao.NewOrderDao().UpdateOrderSettlementMoney(lst[l].Id, money).Err; err == nil { // 订单修改成功
						devInfo := dao.NewOrderDao().GetDeviceInfo(lst[l].DeviceSn).Unwrap().(*devices.DeviceType)            // 获取设备信息
						dingo.Task(NewOrderLogic().CalOrderDividends, func() {}, lst[l], devInfo, money, int64(lst[l].EndAt)) // 重新分红
					}
				}
			}
		}
	}
}


// 机制
// 免押 - 已完成 - 金额大于等于10 - 订单总时长48小时内 - 前5天的订单(结束时间) - 月前的头5天不处理，因为财务要结算
// 套餐线不抽
// 小针管不抽
// 已经抽给中曼的不抽
// 门店天订单小于5笔的不做处理
// 一个门店一天撤销订单大于3
// 合伙人 、 分公司 名下的，多抽点
// 凌晨 5点开始执行

// 假退款完成后，需要删除分红、重新分红


// 200 * 0.2 = 40 * 5 = 200

// 160 * 0.2 = 32 * 5 = 160

// 50 * 0.2 = 10 * 5 = 50

func (t *TaskRefundLogic) UpdatePlaceIsBusinessStatus(isBusiness int, projectLabel string, branchUserId int)  {
	dao.NewPlaceDao().UpdatePlaceIsBusiness(isBusiness, projectLabel, branchUserId)
}

func (t *TaskRefundLogic) UpdateUserChildPlaceIsBusinessStatus(userId int)  {
	ids := dao.NewPlaceDao().GetPlaceIdsByUserId(userId).Unwrap().([]int)
	log.Println(ids)
}

func (t *TaskRefundLogic) GetPlaceIdsByUserId(loginUserId int) []int {
	placesBranchIds := dao.NewUserDao().GetPlacesId(loginUserId).Unwrap().([]int) // 查询用户ID下的所有关联门店
	userIdArr := dao.NewUserDao().QueryChildUserIds(loginUserId).Unwrap().([]int) // 查询用户ID下所有下级用户ID
	placeIdArr := dao.NewPlaceDao().GetPlaceByIds(userIdArr).Unwrap().([]int)     // 下级用户ID 下的门店
	placesBranchIds = append(placesBranchIds, placeIdArr...)                  // 合并门店
	placesIds := utils.RemoveRepByMap(placesBranchIds)                        // 去重门店

	var ids []int
	db := global.Orm.Debug().Table("places").Select("id")
	db.Where("id in (?)", placesIds)

	db.Find(&ids)
	return ids
}




// 余额退款校验
func (t *TaskRefundLogic) ValiteRefundMoney()  {
	dateStr := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
	var mlists []membermodel.MemberPclBalance
	sql := "select * from member_pcl_balance where DATE_FORMAT(create_time,'%Y-%m-%d') >= ? group by member_id"
	global.Orm.Raw(sql, dateStr).Find(&mlists)
	for _, mlst := range mlists {
		memberInfo := memberdao.NewMemberDao().GetMemberInfoById(mlst.MemberId).Unwrap().(*membermodel.MembersModel)

		// 订单余额
		var orderTotal int64
		tsql := "SELECT IFNULL(SUM(amount),0) FROM member_pcl_balance WHERE member_id = ?"
		global.Orm.Raw(tsql, memberInfo.ID).Find(&orderTotal)

		if memberInfo.Balance < 0 {
			updateSql := `UPDATE members SET balance=0 WHERE id=?`
			global.Orm.Exec(updateSql, memberInfo.ID)
		}

		// 订单余额已退，还有余额的
		if memberInfo.Balance > 0 && orderTotal == 0 {
			// 直接修改余额为 0
			updateSql := `UPDATE members SET balance=0 WHERE id=?`
			global.Orm.Exec(updateSql, memberInfo.ID)
			logs.Info("余额大于订单总额=================>", memberInfo.Balance, orderTotal, memberInfo.ID)
		}

		// 订单余额 = 入款余额
		if orderTotal > 0 && memberInfo.Balance > 0 && memberInfo.Balance == orderTotal {

			// 会员对应的订单入帐余额订单列表
			var lists []membermodel.MemberPclBalance
			sql := "select * from member_pcl_balance where member_id = ? and `description` = '订单退款'"
			global.Orm.Raw(sql, memberInfo.ID).Find(&lists)

			for _, lst := range lists {

				orderInfo := dao.NewOrderDao().GetOrderInfoByTradeNo(lst.TradeNo).Unwrap().(*orders.OrderModel)
				refundTotal := decimal.NewFromInt(orderInfo.PayMoney).Sub(decimal.NewFromInt(orderInfo.SettlementMoney)).IntPart()
				// 退款金额 = 入帐金额   且 订单为完成状态
				if refundTotal == int64(lst.Amount) && orderInfo.State == 5 {
					// 订单退款总额
					var refTotal int64
					refsql := "SELECT IFNULL(SUM(refund_fee),0) FROM refunds WHERE trade_no = ?"
					global.Orm.Raw(refsql, lst.TradeNo).Find(&refTotal)

					// 回滚订单
					mpb2 := &membermodel.MemberPclBalance{}
					sql2 := "SELECT * FROM member_pcl_balance WHERE trade_no = ?"
					global.Orm.Raw(sql2, "R" + lst.TradeNo).Find(mpb2)

					// 退款金额 = 入帐金额
					if refTotal == int64(lst.Amount) && mpb2.Id == 0 {
						// 余额回滚
						tx, key := dbs.GormBegin("order refund")
						rechargeMoneyUpdateData := memberdao.NewMemberDao().UpdateBalanceAmount(tx, &membermodel.MemberPclBalance{
							MemberId:    memberInfo.ID,
							Amount:      -int(lst.Amount),
							Type:        4,
							TradeNo:     "R" + lst.TradeNo,
							Description: fmt.Sprintf(`退款提现`),
							CreateTime:  time.Now().Format("2006-01-02 15:04:05"),
							UpdateTime:  time.Now().Format("2006-01-02 15:04:05"),
						})
						if rechargeMoneyUpdateData.Err != nil {
							dbs.GormRollback(tx, key, rechargeMoneyUpdateData.Err)
							continue
						}
						dbs.GormCommit(tx, key)
						logs.Info("回滚订单=================>", refTotal, lst.Amount, memberInfo.Balance, orderTotal, memberInfo.ID)
					}
				}
			}
		}

	}
	//dateStr := time.Now().AddDate(0, 0, -2).Format("2006-01-02")
	//// 获取订单
	//sql := "select * from orders where state = 5 and settlement_money > 0 and pay_money > settlement_money and DATE_FORMAT(FROM_UNIXTIME(end_at),'%Y-%m-%d') >= ?"
	//var lists []orders.OrderModel
	//global.Orm.Raw(sql, dateStr).Find(&lists)
	//for _, lst := range lists {
	//	mpb1 := &membermodel.MemberPclBalance{}
	//	mpb2 := &membermodel.MemberPclBalance{}
	//	var refTotal int64
	//	sql1 := "SELECT * FROM member_pcl_balance WHERE trade_no = ?"
	//	sql2 := "SELECT * FROM member_pcl_balance WHERE trade_no = ?"
	//	refsql := "SELECT IFNULL(SUM(refund_fee),0) FROM refunds WHERE trade_no = ?"
	//	global.Orm.Raw(sql1, lst.TradeNo).Find(mpb1)
	//	global.Orm.Raw(sql2, lst.TradeNo).Find(mpb2)
	//	global.Orm.Raw(refsql, lst.TradeNo).Find(&refTotal)
	//
	//	// 订单余额
	//	var orderTotal int64
	//	tsql := "SELECT IFNULL(SUM(amount),0) FROM member_pcl_balance WHERE trade_no = ? or trade_no = ?"
	//	global.Orm.Raw(tsql, lst.TradeNo, "R"+lst.TradeNo).Find(&orderTotal)
	//
	//	if mpb1.Id > 0 {  // 说明有金额入帐
	//		memberInfo := memberdao.NewMemberDao().GetMemberInfoById(mpb1.MemberId).Unwrap().(*membermodel.MembersModel)
	//		if orderTotal == 0 && memberInfo.Balance >= int64(mpb1.Amount) {
	//
	//		}
	//	}
	//
	//}
}